package cn.jinjimi.domain.data.imp;

import cn.jinjimi.base.util.GsonUtils;
import cn.jinjimi.base.util.StringUtils;
import cn.jinjimi.app.bean.Constants;
import cn.jinjimi.app.controller.event.AddFollowRecordEvent;
import cn.jinjimi.app.controller.event.DataEvent;
import cn.jinjimi.app.controller.event.DeleteFollowRecordEvent;
import cn.jinjimi.app.controller.event.DeleteFollowsRecordPhotosEvent;
import cn.jinjimi.app.controller.event.PhotosListEvent;
import cn.jinjimi.app.controller.event.TodayRemindEvent;
import cn.jinjimi.app.controller.event.UpdateFollowsEvent;
import cn.jinjimi.app.custom.entity.ClueStatistic;
import cn.jinjimi.app.custom.entity.Custom;
import cn.jinjimi.app.custom.entity.CustomFollowsDTO;
import cn.jinjimi.app.custom.entity.CustomLastedFollow;
import cn.jinjimi.app.custom.entity.CustomListDTO;
import cn.jinjimi.app.custom.entity.CustomTagData;
import cn.jinjimi.app.custom.entity.Follow;
import cn.jinjimi.app.custom.entity.Insurance;
import cn.jinjimi.app.custom.entity.Proposal;
import cn.jinjimi.app.custom.entity.UploadCustom;
import cn.jinjimi.app.custom.event.ClueStaticEvent;
import cn.jinjimi.app.custom.event.CustomLastedFollowsEvent;
import cn.jinjimi.app.custom.event.CustomPhotosDelEvent;
import cn.jinjimi.app.custom.event.CustomProposalListEvent;
import cn.jinjimi.app.custom.event.CustomTagGetEvent;
import cn.jinjimi.app.custom.event.InsuranceAddEvent;
import cn.jinjimi.app.custom.event.InsuranceDelEvent;
import cn.jinjimi.app.custom.event.InsuranceEvent;
import cn.jinjimi.app.custom.event.InsuranceUpdateEvent;
import cn.jinjimi.app.custom.event.InsureListEvent;
import cn.jinjimi.app.custom.event.TransferCustomEvent;
import cn.jinjimi.domain.data.Store;
import cn.jinjimi.domain.data.net.API;
import cn.jinjimi.domain.data.net.AppService;
import cn.jinjimi.domain.data.net.CustomerService;
import cn.jinjimi.domain.data.dto.ClueDTO;
import cn.jinjimi.domain.data.dto.ClueStatisticDTO;
import cn.jinjimi.domain.data.dto.CustomImportDTO;
import cn.jinjimi.domain.data.dto.CustomLastedFollowDTO;
import cn.jinjimi.domain.data.dto.CustomTagDTO;
import cn.jinjimi.domain.data.dto.CustomTransferErrorDTO;
import cn.jinjimi.domain.data.dto.CustomerDto;
import cn.jinjimi.domain.data.dto.CustomerTypeDto;
import cn.jinjimi.domain.data.dto.CustomerUpdateDto;
import cn.jinjimi.domain.data.dto.FollowDto;
import cn.jinjimi.domain.data.dto.InsuranceDto;
import cn.jinjimi.domain.data.dto.ProposalDTO;
import cn.jinjimi.domain.data.dto.TransferCustomDTO;
import cn.jinjimi.domain.store.CustomerStore;
import cn.jinjimi.app.entity.PhotoInfo;
import cn.jinjimi.app.entity.PhotoList;
import cn.jinjimi.app.store.entity.custom.ContactInfo;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

/**
 * Created by zhenhua on 16/7/21.
 */
public class CustomerStoreImp extends Store implements CustomerStore {

    @Override
    public String getRemindOfToday() throws IOException {
        API.create(AppService.class).getRemind().enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    if (response.isSuccessful()) {
                        success(TodayRemindEvent.class, response.body().string());
                        return;
                    }
                    fail(TodayRemindEvent.class, response.code(), response.message());
                } catch (IOException e) {
                    e.printStackTrace();
                    fail(TodayRemindEvent.class, 0, "");
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                fail(TodayRemindEvent.class, 0, "");
            }
        });

        return null;
    }

    @Override
    public CustomerDto deleteCustomer(String customerId) throws IOException {
        Response<CustomerDto> response =
                API.create(CustomerService.class)
                        .deleteCustomer(String.valueOf(customerId)).execute();

        return response.isSuccessful() ? response.body() : null;
    }

    @Override
    public Response<CustomerDto> addCustomer(Custom customer, String clueId) throws IOException {

        HashMap<String, RequestBody> data = new HashMap<>();
        MediaType mediaType = MediaType.parse("text/plain");

        data.put("customer.real_name",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.name)));
        data.put("customer.gender",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.gender)));
        data.put("customer.category",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.category)));
        data.put("customer.birthday",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.birthday)));
        data.put("customer.birthday_type",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.birthdayType)));
        data.put("customer.type",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.type)));
        data.put("customer.source",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.source)));
        data.put("customer.agent_id",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.ssoId)));
        data.put("customer.email",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.email)));
        data.put("customer.id_card",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.idCard)));
        data.put("customer.id_code",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.idCode)));
        data.put("customer.province",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.province)));
        data.put("customer.city",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.city)));
        data.put("customer.address",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.address)));
        data.put("customer.remark",
                RequestBody.create(mediaType, StringUtils.emptyOrNot(customer.remark)));

        List<ContactInfo> phones = customer.contactInfos;
        if (phones != null && phones.size() > 0) {
            for (int i = 0, n = phones.size(); i < n; i++) {
                data.put("customer.contact_infos[" + i + "].type", RequestBody.create(mediaType, String.valueOf(phones.get(i).getType())));
                data.put("customer.contact_infos[" + i + "].value", RequestBody.create(mediaType, phones.get(i).getValue()));
            }
        }

        Response<CustomerDto> response = API.create(CustomerService.class).addCustomer(data, clueId).execute();
        return response;
    }

    @Override
    public Response<CustomerDto> updateCustomer(Custom customer) throws IOException {
        List<ContactInfo> phones = customer.getContactInfos();
        final List<CustomerUpdateDto.Contact> contacts = new ArrayList<>();
        if (phones != null && phones.size() > 0) {
            for (ContactInfo p : phones) {
                contacts.add(new CustomerUpdateDto.Contact(p.getType(), p.getValue()));
            }
        }

        List<CustomTagData> tags = customer.labels;
        List<CustomerUpdateDto.Label> labels = new ArrayList<>();
        if (tags != null && tags.size() > 0) {
            for (CustomTagData tag : tags) {
                labels.add(new CustomerUpdateDto.Label(tag.getName()));
            }
        }

        CustomerUpdateDto dto = new CustomerUpdateDto(
                customer.customerId, customer.name,
                customer.birthday, customer.birthdayType, contacts,
                customer.ssoId, customer.type, customer.gender, customer.category,
                customer.label, customer.email,
                customer.idCard, customer.idCode, labels,
                customer.province, customer.city, customer.address, customer.remark);

        Response<CustomerDto> response = API.create(CustomerService.class)
                .updateCustomer(String.valueOf(customer.customerId), dto).execute();

        return response;
    }

    @Override
    public CustomImportDTO importContacts(List<UploadCustom> contacts) throws Exception {

        List<MultipartBody.Part> parts = new ArrayList<>();

        for (int i = 0; i < contacts.size(); i++) {
            UploadCustom item = contacts.get(i);
            parts.add(MultipartBody.Part.createFormData("customers[" + i + "].real_name", StringUtils.isNotEmpty(item.real_name) ? item.real_name : ""));
            parts.add(MultipartBody.Part.createFormData("customers[" + i + "].birthday", StringUtils.isNotEmpty(item.birthday) ? item.birthday : ""));
            parts.add(MultipartBody.Part.createFormData("customers[" + i + "].birthday_type", StringUtils.isNotEmpty(item.birthType) ? item.birthType : ""));

            List<ContactInfo> phones = item.phones;
            if (phones != null && phones.size() > 0) {
                for (int j = 0; j < phones.size(); j++) {
                    parts.add(MultipartBody.Part.createFormData("customers[" + i + "].contact_infos[" + j + "].type",
                            StringUtils.isNotEmpty(String.valueOf(phones.get(j).getType())) ? String.valueOf(phones.get(j).getType()) : ""));
                    parts.add(MultipartBody.Part.createFormData("customers[" + i + "].contact_infos[" + j + "].value",
                            StringUtils.isNotEmpty(String.valueOf(phones.get(j).getValue())) ? String.valueOf(phones.get(j).getValue()) : ""));
                }
            }

            parts.add(MultipartBody.Part.createFormData("customers[" + i + "].source",
                    StringUtils.isNotEmpty(String.valueOf(item.source)) ? String.valueOf(item.source) : ""));
            parts.add(MultipartBody.Part.createFormData("customers[" + i + "].agent_id",
                    StringUtils.isNotEmpty(item.agent_id) ? item.agent_id : ""));

            parts.add(MultipartBody.Part.createFormData("customers[" + i + "].address", StringUtils.isNotEmpty(item.address) ? item.address : ""));
            parts.add(MultipartBody.Part.createFormData("customers[" + i + "].remark", StringUtils.isNotEmpty(item.remark) ? item.remark : ""));

            if (item.headerImg != null && item.headerImg.exists()) {
                parts.add(MultipartBody.Part.createFormData("customers[" + i + "].avatar_name", StringUtils.isNotEmpty(item.fileName) ? item.fileName : ""));

                RequestBody rb = RequestBody.create(MediaType.parse("application/octet-stream"), item.headerImg);
                parts.add(MultipartBody.Part.createFormData("image[" + i + "]", StringUtils.isNotEmpty(item.fileName) ? item.fileName : "", rb));
            }
        }

        Response<CustomImportDTO> response = API.create(CustomerService.class).addContacts(parts).execute();

        CustomImportDTO dto = getHttpState(response, new CustomImportDTO());
        return dto;

    }

    @Override
    public CustomerDto updateCustomerType(String id, int type) throws IOException {
        CustomerTypeDto dto = new CustomerTypeDto(type);
        Response<CustomerDto> response = API.create(CustomerService.class).updateCustomerType(id, dto).execute();

        return response.isSuccessful() ? response.body() : null;
    }

    @Override
    public CustomListDTO getCustomers(long lastModified) throws IOException {
        Response<CustomListDTO> resp = API.create(CustomerService.class).getCustomerList(lastModified).execute();
        return resp.isSuccessful() ? resp.body() : null;
    }

    @Override
    public Response<CustomerDto> getCustomer(String id) throws IOException {
        Response<CustomerDto> response = API.create(CustomerService.class).getCustomer(id).execute();
        return response;
    }

    @Override
    public boolean delFollow(String customerId, String followId) throws IOException {
        Response<ResponseBody> response = API.create(CustomerService.class)
                .deleteFollowRecord(customerId, followId).execute();

        if (response != null && response.isSuccessful()) {
            success(DeleteFollowRecordEvent.class, response.body());
            return true;
        } else if (response != null) {
            fail(DeleteFollowRecordEvent.class, response.code(), response.message());
        } else {
            fail(DeleteFollowRecordEvent.class);
        }

        return false;
    }

    @Override
    public boolean delFollowAttachments(String followId, String... ids) throws IOException {
        //build id string joined with ","
        StringBuilder builder = new StringBuilder();
        for (String id : Arrays.asList(ids)) {
            builder.append(",").append(id);
        }

        Response<ResponseBody> response = API.create(CustomerService.class)
                .deleteFollowAttachment(followId, builder.toString().substring(1)).execute();
        ResponseBody data = parseDataAndDispatchEvents(response, new DeleteFollowsRecordPhotosEvent());
        return data != null;
    }

    @Override
    public boolean delCustomerAttachment(String customerId, String attachmentId) throws IOException {
        Response<ResponseBody> response = API.create(CustomerService.class)
                .deleteCustomerAttachment(String.valueOf(customerId), attachmentId).execute();
        ResponseBody data = parseDataAndDispatchEvents(response, new CustomPhotosDelEvent());
        return data != null;
    }

    @Override
    public Follow putFollow(String customerId, Follow follow) throws IOException {

        Response<FollowDto> response = API.create(CustomerService.class)
                .updateFollow(
                        String.valueOf(customerId),
                        String.valueOf(follow.id),
                        follow.content,
                        String.valueOf(follow.time)).execute();

        FollowDto dto = parseDataAndDispatchEvents(response, new UpdateFollowsEvent());
        return dto == null ? null : dto.follow;
    }

    @Override
    public Follow newFollow(long customerId, String content, long time) throws IOException {
        Response<FollowDto> response = API.create(CustomerService.class)
                .addFollow(customerId, customerId, content, time)
                .execute();

        FollowDto dto = parseDataAndDispatchEvents(response, new AddFollowRecordEvent());
        return dto == null ? null : dto.follow;
    }

    @Override
    public CustomFollowsDTO getFollows(String customerId) throws IOException {
        Response<CustomFollowsDTO> response = API.create(CustomerService.class)
                .getFollows(String.valueOf(customerId))
                .execute();
        return response.isSuccessful() ? response.body() : null;
    }

    @Override
    public Insurance getInsurance(String customerId, String insuranceId) throws IOException {
        return getInsuranceRemote(customerId, insuranceId);
    }

    /**
     * 从服务端获取保单信息
     *
     * @param customerId
     * @param insuranceId
     * @return
     * @throws IOException
     */
    private Insurance getInsuranceRemote(String customerId, String insuranceId) throws IOException {
        Response<Insurance> response = API.create(CustomerService.class)
                .getInsurance(customerId, insuranceId)
                .execute();
        return parseDataAndDispatchEvents(response, new InsuranceEvent());
    }

    @Override
    public List<Insurance> getInsuranceList(String customerId) throws IOException {
        return getInsuranceListRemote(customerId);
    }

    /**
     * 从服务端获取保单列表
     *
     * @param customerId
     * @return
     * @throws IOException
     */
    private List<Insurance> getInsuranceListRemote(String customerId) throws IOException {
        Response<Insurance> response = API.create(CustomerService.class)
                .getInsuranceList(String.valueOf(customerId)).execute();
        Insurance dto = parseDataAndDispatchEvents(response, new InsureListEvent());
        return dto == null ? null : dto.getPolicys();
    }

    @Override
    public Insurance deleteInsurance(String customerId, String insuranceId) throws IOException {

        Response<Insurance> response = API.create(CustomerService.class)
                .deleteInsurance(String.valueOf(customerId), String.valueOf(insuranceId)).execute();
        return parseDataAndDispatchEvents(response, new InsuranceDelEvent());
    }

    @Override
    public Insurance addInsurance(String customerId, String name, long date, int term) throws IOException {
        InsuranceDto dto = new InsuranceDto();
        dto.effect_date = date;
        dto.name = name;
        dto.term = term;

        Response<Insurance> response = API.create(CustomerService.class)
                .addInsurance(customerId, dto).execute();

        return parseDataAndDispatchEvents(response, new InsuranceAddEvent());
    }

    @Override
    public Insurance updateInsurance(String customerId, long effect_date, long insureId, String name, int term) throws IOException {
        InsuranceDto dto = new InsuranceDto();
        dto.effect_date = effect_date;
        dto.name = name;
        dto.id = insureId;
        dto.term = term;
        dto.customer_id = Long.parseLong(customerId);

        Response<Insurance> response = API.create(CustomerService.class)
                .updateInsurance(customerId, String.valueOf(insureId), dto)
                .execute();
        return parseDataAndDispatchEvents(response, new InsuranceUpdateEvent());
    }

    @Override
    public List<CustomTagData> getCustomerTag() throws IOException {
        Response<CustomTagDTO> response = API.create(CustomerService.class)
                .getCustomerTags().execute();
        CustomTagDTO dto = parseDataAndDispatchEvents(response, new CustomTagGetEvent());
        return dto == null ? null : dto.getData();
    }

    @Override
    public List<PhotoInfo> getCustomerPhotosList(String customerId) throws IOException {

        Response<PhotoList> response = API.create(CustomerService.class)
                .getAttachments(String.valueOf(customerId)).execute();
        PhotoList list = parseDataAndDispatchEvents(response, new PhotosListEvent());
        return list == null ? new ArrayList<PhotoInfo>() : list.getAttachements();
    }

    @Override
    public ClueDTO getClues(int page, String source) throws IOException {
        Response<ClueDTO> response = API.create(CustomerService.class)
                .getClues(page, source).execute();

        ClueDTO dto = getHttpState(response, new ClueDTO());
        return dto;
    }

    @Override
    public ClueStatistic getClueStatic() throws IOException {
        Response<ClueStatisticDTO> response = API.create(CustomerService.class)
                .getClueStatistics().execute();
        ClueStatisticDTO dto = parseDataAndDispatchEvents(response, new ClueStaticEvent());
        return dto == null ? null : dto.data;
    }

    @Override
    public List<CustomLastedFollow> getLastedFollowList(int page) throws IOException {
        Response<CustomLastedFollowDTO> response = API.create(CustomerService.class)
                .getLastedFollows(page, Constants.PAGE_LIMIT_20).execute();
        CustomLastedFollowDTO dto = parseDataAndDispatchEvents(response, new CustomLastedFollowsEvent(page));
        return dto == null ? null : dto.data;
    }

    @Override
    public List<Proposal> getProposalList(String customId, int page) throws IOException {
        Response<ProposalDTO> response = API.create(CustomerService.class)
                .getProposals(customId, page, Constants.PAGE_LIMIT_20).execute();
        ProposalDTO dto = parseDataAndDispatchEvents(response, new CustomProposalListEvent(page));
        return dto == null ? null : dto.data;
    }

    @Override
    public Custom transferCustom(String clueId, String customId) throws IOException {
        Response<TransferCustomDTO> response = API.create(CustomerService.class)
                .transferCustom(clueId, customId).execute();
        TransferCustomEvent event = new TransferCustomEvent();
        if (response != null) {
            if (response.isSuccessful()) {
                TransferCustomDTO dto = parseDataAndDispatchEvents(response, event);
                return dto == null ? null : dto.custom;
            } else {
                try {
                    CustomTransferErrorDTO errorDTO = GsonUtils.fromJson(response.errorBody().string(), CustomTransferErrorDTO.class);
                    event.state = DataEvent.FAIL;
                    event.msg = errorDTO.message;
                    dispatch(event);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    return null;
                }
            }
        } else {
            event.state = DataEvent.FAIL;
            dispatch(event);
            return null;
        }
    }
}
